package com.twelve.all.base;

import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.util.SparseArray;
import android.widget.Toast;


import com.twelve.all.nfc.Constants;
import com.twelve.all.nfc.MCReader;
import com.twelve.all.nfc.PreferencesUtil;
import com.twelve.all.nfc.Utils;

import java.io.File;

import static com.twelve.all.nfc.Utils.copyToClipboard;


/**
 * Created by 张龙臣 on 2020/12/14.
 */

public class NFCApp extends Application {

    public static Context mAppContext;
    public static final String HOME_DIR = "/MifareClassicTool";
    public static final String KEYS_DIR = "key-files";
    public static final boolean IS_DONATE_VERSION = false;


    private static SparseArray<byte[][]> mKeyMap = null;
    public static SparseArray<byte[][]> getKeyMap() {
        return mKeyMap;
    }
    public static void setKeyMap(SparseArray<byte[][]> value) {
        mKeyMap = value;
    }

    private static int mHasMifareClassicSupport = 0;

    private static int mKeyMapFrom = -1;
    private static int mKeyMapTo = -1;
    public static void setKeyMapRange (int from, int to){
        mKeyMapFrom = from;
        mKeyMapTo = to;
    }
    public static int getKeyMapRangeFrom() {
        return mKeyMapFrom;
    }
    public static int getKeyMapRangeTo() {
        return mKeyMapTo;
    }


    @Override
    public void onCreate() {
        mAppContext = this;
        super.onCreate();
    }
    /**
     * Check if the user granted read/write permissions to the external storage.
     * @param context The Context to check the permissions for.
     * @return True if granted the permissions. False otherwise.
     */
    public static boolean hasWritePermissionToExternalStorage(Context context) {
        return ContextCompat.checkSelfPermission(context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
                PackageManager.PERMISSION_GRANTED;
    }

    /**
     * Checks if external storage is available for read and write.
     * If not, show an error Toast.
     * @param context The Context in which the Toast will be shown.
     * @return True if external storage is writable. False otherwise.
     */
    public static boolean isExternalStorageWritableErrorToast(
            Context context) {
        if (!isExternalStorageMounted()) {
            Toast.makeText(context, "错误：外部存储器不可读/可写",
                    Toast.LENGTH_LONG).show();
            return false;
        }
        return true;
    }

    /**
     * Checks if external storage is available for read and write.
     * @return True if external storage is writable. False otherwise.
     */
    public static boolean isExternalStorageMounted() {
        return Environment.MEDIA_MOUNTED.equals(
                Environment.getExternalStorageState());
    }
    public static NfcAdapter mNfcAdapter;
    /**
     * The component name of the activity that is in foreground and
     * should receive the new detected tag object by an external reader.
     */
    private static ComponentName mPendingComponentName = null;

    public static void setPendingComponentName(ComponentName pendingActivity) {
        mPendingComponentName = pendingActivity;
    }

    public static void enableNfcForegroundDispatch(Activity targetActivity) {
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {

            Intent intent = new Intent(targetActivity,
                    targetActivity.getClass()).addFlags(
                    Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    targetActivity, 0, intent, 0);
            mNfcAdapter.enableForegroundDispatch(
                    targetActivity, pendingIntent, null, new String[][]{
                            new String[]{NfcA.class.getName()}});
        }
    }

    public static void disableNfcForegroundDispatch(Activity targetActivity) {
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {
            mNfcAdapter.disableForegroundDispatch(targetActivity);
        }
    }

    /**
     * The last detected tag.
     * Set by {@link #treatAsNewTag(Intent, Context)}
     */
    private static Tag mTag = null;
    /**
     * If NFC is disabled and the user chose to use MCT in editor only mode,
     * the choice is remembered here.
     */
    private static boolean mUseAsEditorOnly = false;

    /**
     * The last detected UID.
     * Set by {@link #treatAsNewTag(Intent, Context)}
     */
    private static byte[] mUID = null;

    public static void setTag(Tag tag) {
        mTag = tag;
        mUID = tag.getId();
    }
    public static Tag getTag() {
        return mTag;
    }

    public static int treatAsNewTag(Intent intent, Context context) {
        // Check if Intent has a NFC Tag.
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            tag = MCReader.patchTag(tag);
            setTag(tag);
            Utils.logUid(Utils.byte2Hex(tag.getId()));

            boolean isCopyUID = PreferencesUtil.getPreferences().getBoolean(
                    Constants.AutoCopyUID, false);
            if (isCopyUID) {
                int format = PreferencesUtil.getPreferences().getInt(
                        Constants.UIDFormat, 0);
                String fmtUID =Utils. byte2FmtString(tag.getId(), format);
                // Show Toast with copy message.
                Toast.makeText(context,
                        "UID " + "复制到剪贴板"
                                .toLowerCase() + " (" + fmtUID + ")",
                        Toast.LENGTH_SHORT).show();
                copyToClipboard(fmtUID, context, false);
            } else {
                // Show Toast message with UID.
                String id = "发现新标签" + " (UID: ";
                id +=Utils. byte2Hex(tag.getId());
                id += ")";
//                Toast.makeText(context, id, Toast.LENGTH_LONG).show();
            }
            return Utils.checkMifareClassicSupport(tag, context);
        }
        return -4;
    }
    public static boolean openApp(Context context, String packageName) {
//        PackageManager manager = context.getPackageManager();
//        try {
//            Intent i = manager.getLaunchIntentForPackage(packageName);
//            i.addCategory(Intent.CATEGORY_LAUNCHER);
//            context.startActivity(i);
//            return true;
//        } catch (Exception e) {
//            return false;
//        }
        return false;
    }
    /**
     * Get the App wide used NFC adapter.
     * @return NFC adapter.
     */
    public static NfcAdapter getNfcAdapter() {
        return mNfcAdapter;
    }

    /**
     * Set the App wide used NFC adapter.
     * @param nfcAdapter The NFC adapter that should be used.
     */
    public static void setNfcAdapter(NfcAdapter nfcAdapter) {
        mNfcAdapter = nfcAdapter;
    }

    /**
     * Remember the choice whether to use MCT in editor only mode or not.
     * @param value True if the user wants to use MCT in editor only mode.
     */
    public static void setUseAsEditorOnly(boolean value) {
        mUseAsEditorOnly = value;
    }

    /**
     * If NFC is disabled and the user chose to use MCT in editor only mode,
     * this method will return true.
     * @return True if the user wants to use MCT in editor only mode.
     * False otherwise.
     */
    public static boolean useAsEditorOnly() {
        return mUseAsEditorOnly;
    }
    public static boolean hasMifareClassicSupport() {
        if (mHasMifareClassicSupport != 0) {
            return mHasMifareClassicSupport == 1;
        }

        // Check for the MifareClassic class.
        // It is most likely there on all NFC enabled phones.
        // Therefore this check is not needed.
        /*
        try {
            Class.forName("android.nfc.tech.MifareClassic");
        } catch( ClassNotFoundException e ) {
            // Class not found. Devices does not support MIFARE Classic.
            return false;
        }
        */

        // Check if ther is any NFC hardware at all.
        if (NfcAdapter.getDefaultAdapter(mAppContext) == null) {
            mUseAsEditorOnly = true;
            mHasMifareClassicSupport = -1;
            return false;
        }

        // Check if there is the NFC device "bcm2079x-i2c".
        // Chips by Broadcom don't support MIFARE Classic.
        // This could fail because on a lot of devices apps don't have
        // the sufficient permissions.
        // Another exception:
        // The Lenovo P2 has a device at "/dev/bcm2079x-i2c" but is still
        // able of reading/writing MIFARE Classic tags. I don't know why...
        // https://github.com/ikarus23/MifareClassicTool/issues/152
        boolean isLenovoP2 = Build.MANUFACTURER.equals("LENOVO")
                && Build.MODEL.equals("Lenovo P2a42");
        File device = new File("/dev/bcm2079x-i2c");
        if (!isLenovoP2 && device.exists()) {
            mHasMifareClassicSupport = -1;
            return false;
        }

        // Check if there is the NFC device "pn544".
        // The PN544 NFC chip is manufactured by NXP.
        // Chips by NXP support MIFARE Classic.
        device = new File("/dev/pn544");
        if (device.exists()) {
            mHasMifareClassicSupport = 1;
            return true;
        }

        // Check if there are NFC libs with "brcm" in their names.
        // "brcm" libs are for devices with Broadcom chips. Broadcom chips
        // don't support MIFARE Classic.
        File libsFolder = new File("/system/lib");
        File[] libs = libsFolder.listFiles();
        for (File lib : libs) {
            if (lib.isFile()
                    && lib.getName().startsWith("libnfc")
                    && lib.getName().contains("brcm")
                // Add here other non NXP NFC libraries.
            ) {
                mHasMifareClassicSupport = -1;
                return false;
            }
        }

        mHasMifareClassicSupport = 1;
        return true;
    }
    public static boolean hasExternalNfcInstalled(Context context) {
        return isAppInstalled("eu.dedb.nfc.service", context);
    }

    public static boolean isAppInstalled(String uri, Context context) {
        PackageManager pm = context.getPackageManager();
        try {
            pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
            return true;
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    public static int isExternalNfcServiceRunning(Context context) {
        // getRunningServices() is deprecated since Android 8.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            ActivityManager manager =
                    (ActivityManager) context.getSystemService(
                            Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningServiceInfo service
                    : manager.getRunningServices(Integer.MAX_VALUE)) {
                if ("eu.dedb.nfc.service.NfcService".equals(
                        service.service.getClassName())) {
                    return 1;
                }
            }
            return 0;
        }
        return -1;
    }
}
